package com.wangyu.builder;


import com.wangyu.utils.ObjectParser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Map参数构造器
 *
 * @author Mr.Wang
 * @apiNote 通过重载过滤已知类型的空值，并分别处理
 */
public final class MapParamBuilder {

    private static final String PAGE_KEY = "pageUtil";

    private static final String EMPTY_PATTERN = "{}";

    private Map<String, Object> params;

    private MapParamBuilder() {
        this.params = new HashMap<>();
    }

    public static MapParamBuilder builder() {
        return new MapParamBuilder();
    }

    public static MapParamBuilder of(Map<String, Object> initialParams) {
        MapParamBuilder builder = new MapParamBuilder();
        builder.withAll(initialParams);
        return builder;
    }

    public static MapParamBuilder empty() {
        MapParamBuilder builder = new MapParamBuilder();
        builder.params = Collections.emptyMap();
        return builder;
    }

    @SuppressWarnings("unchecked")
    public static <T> MapParamBuilder of(T bean) {
        if (bean instanceof Map) {
            return of((Map<String, Object>) bean);
        }
        return of(ObjectParser.beanToMap(bean));
    }

    @SuppressWarnings("unchecked")
    public static <T> T any(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return (T) value;
    }

    @SuppressWarnings("unchecked")
    public static <T> T any(Map<String, Object> map, String key, Class<T> tClass) {
        Object value = map.get(key);
        if (tClass.isInstance(value)) {
            return (T) value;
        }
        if (value instanceof Map) {
            return ObjectParser.mapToBean((Map<String, Object>) value, tClass);
        }
        return (T) value;
    }

    public MapParamBuilder with(String key, Object value) {
        if (StringUtils.isNotBlank(key) && value != null) {
            this.params.put(key, value);
        }
        return this;
    }

    public boolean has(String key) {
        return this.params.containsKey(key);
    }

    public MapParamBuilder with(String key, Collection<?> value, Collection<?> defaultValue) {
        if (StringUtils.isNotBlank(key) && CollectionUtils.isNotEmpty(value)) {
            this.params.put(key, value);
        } else {
            this.params.put(key, defaultValue);
        }
        return this;
    }

    public MapParamBuilder with(String key, String value) {
        if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
            this.params.put(key, value);
        }
        return this;
    }

    public MapParamBuilder with(String key, Integer value) {
        // 过滤负值，无意义的值
        if (StringUtils.isNotBlank(key) && value != null) {
            this.params.put(key, value);
        }
        return this;
    }

    /**
     * 交换键位对应的值
     *
     * @param oldKey 要被交换的key
     * @param newKey 要交换的key
     * @return 结果
     */
    public MapParamBuilder exchange(String oldKey, String newKey) {
        if (this.params.containsKey(oldKey) && this.params.containsKey(newKey)) {
            Object oldValue = this.params.get(oldKey);
            Object newValue = this.params.get(newKey);
            this.params.put(oldKey, newValue);
            this.params.put(newKey, oldValue);
        }
        return this;
    }

    /**
     * 替换key为新的key，值不变
     *
     * @param oldKey 旧的key
     * @param newKey 新的key
     * @return 结果
     */
    public MapParamBuilder replace(String oldKey, String newKey) {
        Object value = this.params.get(oldKey);
        if (null != value) {
            this.params.remove(oldKey);
            this.params.put(newKey, value);
        }
        return this;
    }

    public MapParamBuilder clear(String key) {
        this.params.remove(key);
        return this;
    }

    public MapParamBuilder with(String key, Long value) {
        // 过滤负值，无意义的值
        if (StringUtils.isNotBlank(key) && value != null) {
            this.params.put(key, value);
        }
        return this;
    }

    public MapParamBuilder withAll(Map<String, ?> params) {
        if (MapUtils.isNotEmpty(params)) {
            params.forEach(this::with);
        }
        return this;
    }

    public MapParamBuilder withPage(Map<String, Object> params) {
        if (params.containsKey(PAGE_KEY)) {
            this.params.put("page", params.get(PAGE_KEY));
        }
        return this;
    }

    @SuppressWarnings("unchecked")
    public <T> T take(String key) {
        return (T) this.params.get(key);
    }

    public boolean isEmpty() {
        return MapUtils.isEmpty(params);
    }

    public Map<String, Object> build() {
        return this.params;
    }

    @Override
    public String toString() {
        if (MapUtils.isEmpty(this.params)) {
            return EMPTY_PATTERN;
        }
        return ObjectParser.toJSON(this.params);
    }
}
